<template>
  <div class="chat-input-area">
    <div
      :class="['edit-chat-container', isEmpty ? '' : 'not-empty']"
      contenteditable="true"
      @paste.prevent="onPaste"
      @keydown="onKeydown"
      @compositionstart="compositionFlag = true"
      @compositionend="onCompositionEnd"
      @input="onEditorInput"
      @mousedown="onMousedown"
      ref="content"
      @blur="onBlur"
    ></div>
    <chat-at-box
      ref="atBox"
      @select="onAtSelect"
      :search-text="atSearchText"
      :ownerId="ownerId"
      :members="groupMembers"
    ></chat-at-box>
  </div>
</template>
<script setup lang="ts" name="chat-input">
import chatAtBox from "@/views/chat/chatAtBox.vue";
import { useChatStore } from "@/store/chatStore";
import ChatType from "@/utils/ChatType";
import {
  ref,
  onMounted,
  getCurrentInstance,
  defineProps,
  toRefs,
  defineExpose,
  nextTick,
  computed,
} from "vue";
const { proxy } = getCurrentInstance();
const chatStore = useChatStore();
const props = defineProps({
  // 传入的参数
  ownerId: {
    type: String,
    default: () => "",
  },
});
const { ownerId } = toRefs(props);
const groupMembers = ref([]);

//当前聊天
const chat = computed((): Chat => {
  return chatStore.chats[chatStore.index];
});
onMounted(() => {
  // show.value = true;
  setTimeout(() => {
    groupMembers.value = chatStore.getChatUsers(chat.value.id);
    console.log("showAtBox", groupMembers.value, chat.value.id);
  }, 200);
});
/////////////////////////////////////////////////////////////////////////////////////////////////// 添加输入框 加表情和@功能
// 记录光标所在位置
const atBox = ref();
const atIng = ref(false);
const atSearchText = ref("");
// @成员选择
const onAtSelect = (member) => {
  console.log("member", member);

  atIng.value = false;
  // 选中输入的 @xx 符
  const blurRange = blurRanges.value;
  const endContainer = blurRange.endContainer;
  const startOffset = endContainer.data.indexOf("@" + atSearchText.value);
  const endOffset = startOffset + atSearchText.value.length + 1;
  blurRange.setStart(blurRange.endContainer, startOffset);
  blurRange.setEnd(blurRange.endContainer, endOffset);
  blurRange.deleteContents();
  blurRange.collapse();
  console.log("onAtSelect");
  focus();
  // 创建元素节点
  const element = document.createElement("SPAN");
  element.className = "chat-at-user";
  element.dataset.id = member.id;
  element.contentEditable = "false";
  element.innerText = `@${member.nickName}-${member.name}`;
  blurRange.insertNode(element);
  // 光标移动到末尾
  blurRange.collapse();

  // 插入空格
  const textNode = document.createTextNode("\u00A0");
  blurRange.insertNode(textNode);

  blurRange.collapse();
  atSearchText.value = "";
  selectElement(textNode, 1);
};

const onKeydown = (e) => {
  if (e.keyCode === 13) {
    e.preventDefault();
    e.stopPropagation();
    if (atIng.value) {
      console.log("选中at的人");
      atBox.value.select();
      return;
    }
    if (e.ctrlKey) {
      const line = newLine();
      const after = document.createTextNode("\u00A0");
      line.appendChild(after);
      selectElement(line.childNodes[0], 0);
    } else {
      // 中文输入标记
      if (compositionFlag.value) {
        return;
      }
      submit();
    }
    return;
  }
  // 删除键
  if (e.keyCode === 8) {
    console.log("delete");
    // 等待dom更新
    setTimeout(() => {
      const s = content.value.innerHTML.trim();
      // 空dom时，需要刷新dom
      console.log(s);
      if (s === "" || s === "<br>" || s === "<div>&nbsp;</div>") {
        // 拼接随机长度的空格，以刷新dom
        empty();
        isEmpty.value = true;
        selectElement(content.value);
      } else {
        isEmpty.value = false;
      }
    });
  }
  // at框打开时，上下键移动特殊处理
  if (atIng.value) {
    if (e.keyCode === 38) {
      e.preventDefault();
      e.stopPropagation();
      atBox.value.moveUp();
    }
    if (e.keyCode === 40) {
      e.preventDefault();
      e.stopPropagation();
      atBox.value.moveDown();
    }
  }
};

const content = ref();
const focus = () => {
  content.value.focus();
};

// 记录光标位置
const isEmpty = ref(true);
const changeStored = ref(false);
const compositionFlag = ref(false); // 中文输入标记

const onCompositionEnd = (e) => {
  compositionFlag.value = false;
  onEditorInput(e);
};
const onEditorInput = (e) => {
  isEmpty.value = false;
  changeStored.value = false;
  console.log(
    "onEditorInput",
    e,
    "groupMembers",
    groupMembers.value,
    "compositionFlag",
    compositionFlag.value,
  );
  if (!groupMembers.value) {
    groupMembers.value = chatStore.getChatUsers(chat.value.id);
  }

  if (groupMembers.value && !compositionFlag.value) {
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    // 截取@后面的名称作为过滤条件，并以空格结束
    const endContainer = range.endContainer;
    const endOffset = range.endOffset;
    const textContent = endContainer.textContent;
    let startIndex = -1;
    for (let i = endOffset; i >= 0; i--) {
      if (textContent[i] === "@") {
        startIndex = i;
        break;
      }
    }
    // 没有at符号，则关闭弹窗
    if (startIndex === -1) {
      atBox.value.close();
      return;
    }

    let endIndex = endOffset;
    for (let i = endOffset; i < textContent.length; i++) {
      if (textContent[i] === " ") {
        endIndex = i;
        break;
      }
    }
    atSearchText.value = textContent.substring(startIndex + 1, endIndex).trim();
    // 打开选择弹窗
    console.log(
      "检查输入框内容 -atSearchText",
      atSearchText.value,
      "textContent",
      textContent,
    );
    // 加个判断 是否是群组
    if (atSearchText.value == "" && chat.value.type === ChatType.GROUP) {
      //at 功能隐藏
      // showAtBox(e);
    }
  }
};

const showAtBox = (e) => {
  atIng.value = true;

  // show之后会自动更新当前搜索的text
  // this.atSearchText = "";
  const selection = window.getSelection();
  const range = selection.getRangeAt(0);
  // 光标所在坐标
  const pos = range.getBoundingClientRect();
  atBox.value.open({
    x: pos.x,
    y: pos.y,
  });
  // 记录光标所在位置
  updateRange();
};

const onBlur = (e) => {
  console.log("onBlur", e);

  updateRange();
};
const blurRanges = ref();

const updateRange = () => {
  const selection = window.getSelection();
  console.log("111111111111");

  blurRanges.value = selection.getRangeAt(0);
};
// 插入元素
const selectElement = (element, endOffset) => {
  const selection = window.getSelection();
  // 插入元素可能不是立即执行的，vue可能会在插入元素后再更新dom
  nextTick(() => {
    const t1 = document.createRange();
    t1.setStart(element, 0);
    t1.setEnd(element, endOffset || 0);
    if (element.firstChild) {
      t1.selectNodeContents(element.firstChild);
    }
    t1.collapse();
    selection.removeAllRanges();
    selection.addRange(t1);
    // 需要时自动聚焦
    if (element.focus) {
      element.focus();
    }
  });
};

const newLine = () => {
  const selection = window.getSelection();
  const range = selection.getRangeAt(0);
  const divElement = document.createElement("div");
  const endContainer = range.endContainer;
  const parentElement = endContainer.parentElement;
  if (parentElement.parentElement === content.value) {
    divElement.innerHTML = endContainer.textContent
      .substring(range.endOffset)
      .trim();
    endContainer.textContent = endContainer.textContent.substring(
      0,
      range.endOffset,
    );
    // 插入到当前div（当前行）后面
    parentElement.insertAdjacentElement("afterend", divElement);
  } else {
    divElement.innerHTML = "";
    content.value.append(divElement);
  }
  return divElement;
};

const imageList = ref([]);
const fileList = ref([]);
const clear = () => {
  empty();
  imageList.value = [];
  fileList.value = [];
};
const empty = () => {
  content.value.innerHTML = "";
  const line = newLine();
  const after = document.createTextNode("\u00A0");
  line.appendChild(after);
  nextTick(() => selectElement(after));
};
const emit = defineEmits(["submit"]);
// 动态输入内容
const onInput = (text) => {
  const nodes = content.value;
  nodes.innerText = nodes.innerText + text;
};

// 内容 提交
const submit = () => {
  console.log("submit", content.value.innerHTML);

  const nodes = content.value.childNodes;
  const fullList = [];
  let tempText = "";
  let atUserIds = [];
  const each = (nodes) => {
    for (let i = 0; i < nodes.length; i++) {
      const node = nodes[i];
      if (!node) {
        continue;
      }
      if (node.nodeType === 3) {
        tempText += html2Escape(node.textContent);
        continue;
      }
      const nodeName = node.nodeName.toLowerCase();
      if (nodeName === "script") {
        continue;
      }
      const text = tempText.trim();
      if (nodeName === "img") {
        const imgId = node.dataset.imgId;
        if (imgId) {
          if (text) {
            fullList.push({
              type: "text",
              content: text,
              atUserIds: atUserIds,
            });
            tempText = "";
            atUserIds = [];
          }
          fullList.push({
            type: "image",
            content: imageList.value[imgId],
          });
        } else {
          const emojiCode = node.dataset.emojiCode;
          tempText += emojiCode;
        }
      } else if (nodeName === "div") {
        const fileId = node.dataset.fileId;
        // 文件
        if (fileId) {
          if (text) {
            fullList.push({
              type: "text",
              content: text,
              atUserIds: atUserIds,
            });
            tempText = "";
            atUserIds = [];
          }
          fullList.push({
            type: "file",
            content: fileList[fileId],
          });
        } else {
          tempText += "\n";
          each(node.childNodes);
        }
      } else if (nodeName === "span") {
        if (node.dataset.id) {
          tempText += node.innerHTML;
          atUserIds.push(node.dataset.id);
        } else if (node.outerHtml) {
          tempText += node.outerHtml;
        }
      }
    }
  };
  each(nodes);
  const text = tempText.trim();
  if (text !== "") {
    fullList.push({
      type: "text",
      content: text,
      atUserIds: atUserIds,
    });
  }
  emit("submit", fullList);
};
const html2Escape = (strHtml) => {
  return strHtml.replace(/[<>&"]/g, function (c) {
    return {
      "<": "&lt;",
      ">": "&gt;",
      "&": "&amp;",
      '"': "&quot;",
    }[c];
  });
};
defineExpose({
  focus,
  clear,
  blur,
  submit,
  onInput,
});
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 结束
</script>
<style lang="scss" scoped>
.chat-input-area {
  .edit-chat-container {
    height: 8rem;
    padding: 10px 10px 5px 10px;
  }
  :deep(.chat-at-user) {
    color: #f0f;
  }
}
</style>
